<?php

/**
 * Bootstraps the module used in the current request
 * It merges the options from main application.ini with the options from a
 * module specific application.ini.
 * I'm using the fact that a resources are loaded only once, so a resource
 * declared in main application.ini is initialized there. If you wish to use some resource
 * in every module use the key default (see bellow).
 *
 * The keys default and disable in the main application.ini have a special meaning.
 * default: It is merged initally so a key default.resources.xxx is added as resource.xxx
 *          so it load the resource xxx as a default for all modules
 * disable: It is used to disable keys after merging so a key disable.resources.xxx disables
 *          this resource in all modules.
 */
class Ext_Controller_Plugin_ModuleBootstrap extends Zend_Controller_Plugin_Abstract
{
    const MODULE_APPLICATION_INI = "configs/application.ini";

    protected $_bootstrap;

    protected $_autoloader;

    public function dispatchLoopStartup( Zend_Controller_Request_Abstract $request )
    {
        $moduleName = $request->getModuleName();
        if ( empty( $moduleName ) ) {
            $moduleName = 'default';
        }

        $front = Zend_Controller_Front::getInstance();
        $moduleDir = $front->getModuleDirectory( $moduleName );
        if ( empty( $moduleDir ) ) {
            $moduleDir = APPLICATION_PATH;
        }
        
        // Para ser usado en los ini.
        define('MODULE_PATH', $moduleDir );
        define('MODULE_NAME', $moduleName );

        // Create a autoloader for this module
        $autoloader = new Zend_Application_Module_Autoloader(array(
            'namespace' => $moduleName,
            'basePath'  => $moduleDir,
            ));


        $this->_bootstrap = $front->getParam('bootstrap');
        $globalOptions = $this->_bootstrap->getOptions();

        // Default options from main application.ini
        $options = array();
        if ( isset( $globalOptions['default'] ) ) {
            $options = $globalOptions['default'];
        }
        if ( isset( $globalOptions[ $moduleName ] ) ) {
            $options = $this->_bootstrap->mergeOptions($options, $globalOptions[ $moduleName ]);
        }


        $applicationFile = $moduleDir . DIRECTORY_SEPARATOR . self::MODULE_APPLICATION_INI;
        if ( isset( $globalOptions[ 'application_file' ] ) ) {
            $applicationFile  = $moduleDir . DIRECTORY_SEPARATOR . $globalOptions[ 'application_file' ];
        }
        $options = $this->_bootstrap->mergeOptions( $options, $this->_loadConfig( $applicationFile ) );
        if ( isset( $globalOptions['disable'] ) ) {
            $options = $this->unsetOptions($options, $globalOptions['disable'] );
        }
        $this->_bootstrap->setOptions( $options );
        $this->_bootstrap->bootstrap();
    }



    /**
     * Unset options recursively.
     *
     * @param  array $array1
     * @param  mixed $array2
     * @return array
     */
    public function unsetOptions(array $array1, $array2 = null)
    {
        if (is_array($array2)) {
            foreach ($array2 as $key => $val) {
                if ( ! isset( $array1[ $key ] ) ) {
                    continue;
                }
                if ( is_array( $array2[ $key ] ) ) {
                    $array1[ $key ] = $this->unsetOptions( $array1[ $key ], $array2[ $key ]);
                } else {
                    unset( $array1[ $key ] );
                }
            }
        }
        return $array1;
    }

   /**
     * Based heavily on Zend_Application->_loadConfig
     * Load configuration file of options
     *
     * @param  string $file
     * @throws Zend_Application_Exception When invalid configuration file is provided
     * @return array
     */
    protected function _loadConfig($file)
    {
        if (! Zend_Loader::isReadable($file) ) {
            return;
        }
        $environment = $this->_bootstrap->getApplication()->getEnvironment();
        $suffix      = strtolower(pathinfo($file, PATHINFO_EXTENSION));

        switch ($suffix) {
            case 'ini':
                $config = new Zend_Config_Ini($file, $environment);
                break;

            case 'xml':
                $config = new Zend_Config_Xml($file, $environment);
                break;

            case 'php':
                case 'inc':
                    $config = include $file;
                    if (!is_array($config)) {
                        throw new Zend_Application_Exception('Invalid configuration file provided; PHP file does not return array value');
                    }
                    return $config;
                    break;

                default:
                    throw new Zend_Application_Exception('Invalid configuration file provided; unknown config type');
                    break;
            }
            return $config->toArray();
        }

    }


